#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>

//#define DEFAULTIP "127.0.0.1"
#define DEFAULTIP "192.168.2.59"
#define DEFAULTPORT "80"
#define DEFAULTBACK "10"
#define DEFAULTDIR "/home"
#define DEFAULTLOG "/tmp/das-server.log"
#define DEFAULTFILEPATH "/lxi/identification"
#define NEWFILEPATH "/lxi/identification/Identification.xml"
#define DEFAULTHOMEPATH "/"
#define HOMEPATH "/WB1000_WelcomePage.html"

void prterrmsg(char *msg);
#define prterrmsg(msg)        { perror(msg); abort(); }
void wrterrmsg(char *msg);
#define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }

void prtinfomsg(char *msg);
#define prtinfomsg(msg)        { fputs(msg, stdout);  }
void wrtinfomsg(char *msg);
#define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}

#define MAXBUF        1024

char buffer[MAXBUF + 1];
char *host = 0;
char *port = 0;
char *back = 0;
char *dirroot = 0;
char *logdir = 0;
unsigned char daemon_y_n = 0;
FILE *logfp;

#define MAXPATH        150

/*----------------------------------------
 *--- dir_up - 查找dirpath所指目录的上一级目录
 *----------------------------------------
 */
char *dir_up(char *dirpath)
{
    static char Path[MAXPATH];
    int len;

    strcpy(Path, dirpath);
    len = strlen(Path);
    if (len > 1 && Path[len - 1] == '/')
        len--;
    while (Path[len - 1] != '/' && len > 1)
        len--;
    Path[len] = 0;
    return Path;
}

/*------------------------------------------------------
 *--- AllocateMemory - 分配空间并把d所指的内容复制
 *------------------------------------------------------
 */
void AllocateMemory(char **s, int l, char *d)
{
    *s = malloc(l + 1);
    bzero(*s, l + 1);
    memcpy(*s, d, l);
}
/************关于本文档********************************************
*filename: das-server.c
*purpose: 这是在Linux下用C语言写的目录访问服务器，支持目录浏览和文件下载
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-26 19:32
*Note: 任何人可以任意复制代码并运用这些文档，当然包括你的商业用途
* 但请遵循GPL
*Thanks to: Google.com
*Hope:希望越来越多的人贡献自己的力量，为科学技术发展出力
* 科技站在巨人的肩膀上进步更快！感谢有开源前辈的贡献！
*********************************************************************/
/*------------------------------------------------------
 *--- GiveResponse - 把Path所指的内容发送到client_sock去
 *-------------------如果Path是一个目录，则列出目录内容
 *-------------------如果Path是一个文件，则下载文件
 *------------------------------------------------------
 */
void GiveResponse(FILE * client_sock, char *req_file_path)
{
    struct dirent *dirent;
    struct stat info;
    char Filename[MAXPATH];
    DIR *dir;
    int fd, len, ret;
    char *p, *realPath, *realFilename, *nport;

    /*  */
    printf("GiveResponse-req_file_path = %s\n", req_file_path);
    if(strcmp(req_file_path, DEFAULTFILEPATH) == 0){
//    	req_file_path = DEFAULTFILEPATH;
    	fprintf(client_sock, \
    			"HTTP/1.0 302 Redirect\r\n" \
    			"Server: GoAhead-Webs\r\n" \
    			"Date: Wed Dec 31 23:59:59 1969\r\n" \
    			"Pragma: no-cache\r\n" \
    			"Cache-Control: no-cache\r\n" \
    			"Content-Type: text/html\r\n" \
    			"Location: http://192.168.1.55/lxi/identification/Identification.xml\r\n\r\n");
    	fflush(client_sock);
    	fprintf(client_sock, \
    			"<html><head></head><body>\r\n" \
				"\t\tThis document has moved to a new <a href=\"http://192.168.1.55/lxi/identification/Identification.xml\">location</a>.\r\n" \
				"\t\tPlease update your documents to reflect the new location.\r\n" \
				"\t\t</body></html>\r\n\r\n");
    	fflush(client_sock);
        printf("WRONG PATH!\n");
        return;
    }
    else if(strcmp(req_file_path, NEWFILEPATH) == 0){
    	fprintf(client_sock,
    			"HTTP/1.0 200 OK\r\n" \
				"Date: Wed Dec 31 23:59:59 1969\r\n" \
				"Server: GoAhead-Webs\r\n");
		fflush(client_sock);
    	fprintf(client_sock,
				"Last-modified: Thu Jan  1 00:00:00 1970\r\n" \
				"Content-length: 1458\r\n" \
				"Content-type: text/xml\r\n" \
				"\r\n" \
				"<?xml version=\"1.0\" encoding=\"GB2312\"?>" \
				"<LXIDevice xmlns=\"http://www.lxistandard.org/InstrumentIdentification/1.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.lxistandard.org/InstrumentIdentification/1.0\n" \
					"http://192.168.1.55/lxi/identification/LXIIdentification.xsd\">" \
					"<Manufacturer>Rigol Technologies</Manufacturer>" \
					"<Model>DSA1020</Model>" \
					"<SerialNumber>DSA1D122300071</SerialNumber>" \
					"<FirmwareRevision>00.01.03.01.</FirmwareRevision>" \
					"<ManufacturerDescription>Rigol</ManufacturerDescription>" \
					"<HomepageURL>http://www.rigolna.com</HomepageURL>" \
					"<DriverURL>http://www.rigolna.com</DriverURL>" \
					"<UserDescription>DSA1030 Identification Schema</UserDescription>" \
					"<IdentificationURL>http://192.168.1.55/lxi/identification</IdentificationURL>" \
					"<Interface xsi:type=\"NetworkInformation\" InterfaceType=\"LXI\" IPType=\"IPv4\" InterfaceName=\"eth0\">" \
						"<InstrumentAddressString>TCPIP0::192.168.1.55::INSTR</InstrumentAddressString>" \
						"<Hostname>192.168.1.55</Hostname>" \
						"<IPAddress>192.168.1.55</IPAddress>" \
						"<SubnetMask>255.255.255.0</SubnetMask>" \
						"<MACAddress></MACAddress>" \
						"<Gateway>192.168.1.1</Gateway>" \
						"<DHCPEnabled>false</DHCPEnabled>" \
						"<AutoIPEnabled>false</AutoIPEnabled>" \
					"</Interface>" \
					"<Interface InterfaceType=\"Rigol Custom Network Interface\" InterfaceName=\"LAN\">" \
						"<InstrumentAddressString>192.168.1.55</InstrumentAddressString>" \
					"</Interface>" \
					"<IVISoftwareModuleName>RGDSA</IVISoftwareModuleName>" \
					"<LXIClass>C</LXIClass>" \
					"<Domain>1</Domain>" \
					"<LXIVersion>1.2</LXIVersion>" \
				"</LXIDevice>");
    	fflush(client_sock);
		printf("RIGHT PATH!\n");
		return;
	}
    else if(strcmp(req_file_path, DEFAULTHOMEPATH) == 0){
    	fprintf(client_sock,
				"HTTP/1.0 302 Redirect\r\n" \
				"Server: GoAhead-Webs\r\n" \
				"Date: Wed Dec 31 23:59:59 1969\r\n" \
				"Pragma: no-cache\r\n" \
				"Cache-Control: no-cache\r\n" \
				"Content-Type: text/html\r\n" \
				"Location: http://192.168.1.55/WB1000_WelcomePage.html\r\n\r\n");
		fflush(client_sock);
    	fprintf(client_sock, \
    			"<html><head></head><body>\r\n" \
				"\t\tThis document has moved to a new <a href=\"http://192.168.1.55/WB1000_WelcomePage.html\">location</a>.\r\n" \
				"\t\tPlease update your documents to reflect the new location.\r\n" \
				"\t\t</body></html>\r\n\r\n");
    	fflush(client_sock);
		printf("HOMEPATH REGUEST!\n");
		return;
	}
	else if(strcmp(req_file_path, HOMEPATH) == 0){
		fprintf(client_sock,
				"HTTP/1.0 200 OK\r\n" \
				"Date: Wed Dec 31 23:59:59 1969\r\n" \
				"Server: GoAhead-Webs\r\n" \
				"Pragma: no-cache\r\n" \
				"Cache-Control: no-cache\r\n" \
				"Expires: Wed Dec 31 23:59:59 1969\r\n" \
				"Content-length: 4480\r\n" \
				"Content-type: text/html\r\n\r\n");
		fflush(client_sock);
		fprintf(client_sock,
				"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"" \
				"\"http://www.w3.org/TR/html4/loose.dtd\">" \
				"<html>" \
				"<head>" \
				"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">" \
				"<link href=\"defultcss.css\" rel=\"stylesheet\" type=\"text/css\">" \
				"<link href=\"WB1000WelcomePage.css\" rel=\"stylesheet\" type=\"text/css\">" \
				"<title>RIGOL DSA Welcome Page    </title>" \
				"<style type=\"text/css\">" \
				"<!--\"" \
				"-->\"" \
				"</style></head>\"" \
				"<body>\"" \
				     "<div class=\"top\">" \
					    "<div class=\"top_1\">" \
						    "<a href=\"http://www.rigolna.com\" target=\"_blank\">RIGOL Web</a><a>&nbsp;&nbsp;|&nbsp;&nbsp;</a><a href=\"http://www.rigolna.com/products.aspx\">Products</a><a>&nbsp;&nbsp;|&nbsp;&nbsp;</a><a href=\"http://www.rigolna.com/support.aspx\">Service & Support</a><a>&nbsp;&nbsp;&nbsp;&nbsp;</a>" \
					   "</div>" \
					    "<div class=\"top_2\">" \
				            "<div class=\"top_logo\"><img src=\"images/logo.jpg\" border=\"0\" alt=\"logo\" ></div>" \
				            "<div class=\"top_right\"><img src=\"images/logo_WB1000.jpg\" border=\"0\" alt=\"WB1000\"></div>" \
						"</div>" \
						"<div clatings.html\"></a></div>" \
						"<div class=\"nav_4\"><a href=\"WB1000_WebControl.html\"></a></div>" \
						"<div class=\"nav_5\"><a href=\"WB1000_Help.html\"></a></div>" \
						"<div class=\"nav_6\"><a href=\"WB1000_Security.html\"></a></div>" \
				        "<div class=\"nav_bottom\">" \
				"<div class=\"lxi\"><img src=\"images/lxi.jpg\" border=\"0\" alt=\"lxi.logo\" ></div>" \
						"</div>" \
					"</div>" \
					"<div class=\"content\">" \
				       "<div class=\"contentTxet_1\"><a>Welcome to  Web  of   Spectrum Analyzer       </a></div>" \
						    "<table class=\"vs5000WelcomPageTable\">" \
						       "<tr>" \
						            "<td class=\"vs5000_td\" colspan=\"2\"><b>Information About This Instrument:</b></td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th width=\"40%\">Instrument Model:</th>" \
				                    "<td>DSA1020           </td>" \
				                 "</tr>" \
				                "<tr>" \
				                    "<th>Manufacturer:</th>" \
				                    "<td>Rigol Technologies                    </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>Serial Number:</th>" \
				                    "<td>DSA1D122300071              </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>Description: </th>" \
				                    "<td>DSA1020                                   </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>LXI Class:</th>" \
				                    "<td>C   </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>LXI Version:</th>" \
				                    "<td>1.2     </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>Host Name:</th>" \
				                    "<td>                               </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>MAC Address:</th>" \
				                    "<td>00-19-AF-60-00-C7      </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>IP Address:</th>" \
				                    "<td>192.168.1.54                   </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>Firmware Revision:</th>" \
				                    "<td>00.01.03.01.                   </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>VISA TCP/IP String:</th>" \
				                    "<td>TCPIP0::192.168.1.54::INSTR</td>      " \
				                "</tr>" \
				                "<tr>" \
				                    "<th>Auto-MDIX Capable:</th>" \
				                    "<td>NO  </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>GPIB Address:</th>" \
				                    "<td>                              </td>" \
				                "</tr>" \
				                "<tr>" \
				                    "<th>VISA USB Connect String:</th>" \
				                    "<td>                                             </td>" \
				                "</tr>        " \
				             "</table><form action=\"/cgi-bin/remote_identify.cgi\" method=post name=\"idfy\" " \
				"onsubmit=\"return 'True';\">	 <div class=\"bottom_button\"><input name=\"Identification\" value=\"Web Identification Indicator\"   type=\"submit\"></div> </form>" \
					"</div>" \

				    "<div class=\"bottom\">" \
					   "<div class=\"bottom_font\"><a>&copy;2008 RIGOL Technologies, Inc. All Rights Reserved</a></div>" \

				    "</div>" \
				"</body>" \
				"</html>");
		fflush(client_sock);
		printf("DEFAULTHOMEPATH REGUEST!\n");
		return;
	}
}

/*------------------------------------------------------
 *--- getoption - 分析取出程序的参数
 *------------------------------------------------------
 */
void getoption(int argc, char **argv)
{
    int c, len;
    char *p = 0;

    opterr = 0;
    while (1) {
        int option_index = 0;
        static struct option long_options[] = {
            {"host", 1, 0, 0},
            {"port", 1, 0, 0},
            {"back", 1, 0, 0},
            {"dir", 1, 0, 0},
            {"log", 1, 0, 0},
            {"daemon", 0, 0, 0},
            {0, 0, 0, 0}
        };
        /* 本程序支持如一些参数：
         * --host IP地址 或者 -H IP地址
         * --port 端口 或者 -P 端口
         * --back 监听数量 或者 -B 监听数量
         * --dir 网站根目录 或者 -D 网站根目录
         * --log 日志存放路径 或者 -L 日志存放路径
         * --daemon 使程序进入后台运行模式
         */
        c = getopt_long(argc, argv, "H:P:B:D:L",
                        long_options, &option_index);
        if (c == -1 || c == '?')
            break;

        if(optarg)        len = strlen(optarg);
        else        len = 0;

        if ((!c && !(strcasecmp(long_options[option_index].name, "host")))
            || c == 'H')
            p = host = malloc(len + 1);
        else if ((!c
                  &&
                  !(strcasecmp(long_options[option_index].name, "port")))
                 || c == 'P')
            p = port = malloc(len + 1);
        else if ((!c
                  &&
                  !(strcasecmp(long_options[option_index].name, "back")))
                 || c == 'B')
            p = back = malloc(len + 1);
        else if ((!c
                  && !(strcasecmp(long_options[option_index].name, "dir")))
                 || c == 'D')
            p = dirroot = malloc(len + 1);
        else if ((!c
                  && !(strcasecmp(long_options[option_index].name, "log")))
                 || c == 'L')
            p = logdir = malloc(len + 1);
        else if ((!c
                  &&
                  !(strcasecmp
                    (long_options[option_index].name, "daemon")))) {
            daemon_y_n = 1;
            continue;
        }
        else
            break;
        bzero(p, len + 1);
        memcpy(p, optarg, len);
    }
}

void http_pthread(int argc, char **argv)
{
    struct sockaddr_in svr_addr;
    int sock_fd, addrlen;

    /* 获得程序工作的参数，如 IP 、端口、监听数、网页根目录、目录存放位置等 */
    getoption(argc, argv);

    if (!host) {
        addrlen = strlen(DEFAULTIP);
        AllocateMemory(&host, addrlen, DEFAULTIP);
    }
    if (!port) {
        addrlen = strlen(DEFAULTPORT);
        AllocateMemory(&port, addrlen, DEFAULTPORT);
    }
    if (!back) {
        addrlen = strlen(DEFAULTBACK);
        AllocateMemory(&back, addrlen, DEFAULTBACK);
    }
    if (!dirroot) {
        addrlen = strlen(DEFAULTDIR);
        AllocateMemory(&dirroot, addrlen, DEFAULTDIR);
    }
    if (!logdir) {
        addrlen = strlen(DEFAULTLOG);
        AllocateMemory(&logdir, addrlen, DEFAULTLOG);
    }

    printf("http_thread\n");
    /* fork() */
    if (daemon_y_n) {
        if (fork())
            exit(0);
        if (fork())
            exit(0);
        close(0), close(1), close(2);
        logfp = fopen(logdir, "a+");
        if (!logfp)
            exit(0);
    }
		printf("\nhost=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n", \
			 host, port, back, dirroot, logdir, (daemon_y_n?" ":" 不"), getpid());

    /* 处理子进程退出以免产生僵尸进程 */
    signal(SIGCHLD, SIG_IGN);

    /* socket */
    if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
        if (!daemon_y_n) {
            prterrmsg("socket()");
        } else {
            wrterrmsg("socket()");
        }
    }
    /*  */
    addrlen = 1;
    setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));

    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(atoi(port));
    svr_addr.sin_addr.s_addr = inet_addr(host);
    addrlen = sizeof(struct sockaddr_in);
    /*  */
    if (bind(sock_fd, (struct sockaddr *) &svr_addr, addrlen) < 0) {
        if (!daemon_y_n) {
            prterrmsg("bind()");
        } else {
            wrterrmsg("bind()");
        }
    }

    /* */
    if (listen(sock_fd, atoi(back)) < 0) {
        if (!daemon_y_n) {
            prterrmsg("listen()");
        } else {
            wrterrmsg("listen()");
        }
    }
    while (1) {
        int len;
        int new_fd;
        addrlen = sizeof(struct sockaddr_in);
        /*  */
        new_fd = accept(sock_fd, (struct sockaddr *) &svr_addr, &addrlen);
//        printf("new_fd = %d\n", new_fd);
        if (new_fd < 0) {
            if (!daemon_y_n) {
                prterrmsg("accept()");
            } else {
                wrterrmsg("accept()");
            }
            break;
        }
        bzero(buffer, MAXBUF + 1);
        sprintf(buffer, "连接来自于: %s:%d\n", inet_ntoa(svr_addr.sin_addr), ntohs(svr_addr.sin_port));
        if (!daemon_y_n) {
            prtinfomsg(buffer);
        } else {
            wrtinfomsg(buffer);
        }
        /*  */
        if (!fork()) {
            bzero(buffer, MAXBUF + 1);
            if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) {
                FILE *ClientFP = fdopen(new_fd, "w");
                if (ClientFP == NULL) {
                    if (!daemon_y_n) {
                        prterrmsg("fdopen()");
                    } else {
                        prterrmsg("fdopen()");
                    }
                } else {
                    char Req[MAXPATH + 1] = "";
                    sscanf(buffer, "GET %s HTTP", Req);
                    bzero(buffer, MAXBUF + 1);
                    sprintf(buffer, "请求取文件: \"%s\"\n", Req);
                    printf("get file buffer = %s\n", buffer);
                    if (!daemon_y_n) {
                        prtinfomsg(buffer);
                    } else {
                        wrtinfomsg(buffer);
                    }
                    /* */
                    GiveResponse(ClientFP, Req);
                    fclose(ClientFP);
                }
            }
            exit(0);
        }
        close(new_fd);
    }
    close(sock_fd);
    printf("http prog exit!\n");
//    return 0;
}
